package system

import (
	"context"
	"database/sql"
	"errors"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"
	"server/internal/consts"
	"server/internal/dao"
	"server/internal/model"
	"server/internal/model/do"
	"server/internal/model/entity"
	"server/internal/service"
)

type sSystemConfig struct {
}

func init() {
	service.RegisterSystemConfig(&sSystemConfig{})
}

func (s *sSystemConfig) Create(ctx context.Context, in model.SystemConfigCreateInput) (newID int64, err error) {
	if !s.checkContentIsValid(ctx, in.Code, in.Content) {
		return 0, gerror.New("配置项内容格式错误")
	}
	if err = s.checkCodeIsRepeat(ctx, in.Code, 0); err != nil {
		return 0, err
	}
	newID, err = dao.SystemConfig.Ctx(ctx).Data(do.SystemConfig{
		CategoryId:    in.CategoryId,
		Code:          in.Code,
		Name:          in.Name,
		Content:       in.Content,
		CreatedBy:     service.SystemLogin().GetAdminID(ctx),
		Remark:        in.Remark,
		IsAllowDelete: in.IsAllowDelete,
	}).InsertAndGetId()
	if err != nil {
		return
	}
	if err = s.FlushCache(ctx, []string{in.Code}); err != nil {
		return
	}
	return
}

func (s *sSystemConfig) checkCodeIsRepeat(ctx context.Context, code string, id int64) error {
	where := g.Map{
		"code": code,
	}
	if id > 0 {
		where["id <> ?"] = id
	}
	count, err := dao.SystemConfig.Ctx(ctx).Where(where).Count()
	if err != nil {
		return err
	}
	if count > 0 {
		return gerror.New("配置项 重复")
	}
	return nil
}

func (s *sSystemConfig) UpdateByID(ctx context.Context, id int64, in model.SystemConfigUpdateInput) (err error) {
	if !s.checkContentIsValid(ctx, in.Code, in.Content) {
		return gerror.New("配置项内容格式错误")
	}
	if err = s.checkCodeIsRepeat(ctx, in.Code, id); err != nil {
		return err
	}
	_, err = dao.SystemConfig.Ctx(ctx).Data(do.SystemConfig{
		CategoryId:    in.CategoryId,
		Code:          in.Code,
		Name:          in.Name,
		Content:       in.Content,
		Remark:        in.Remark,
		UpdatedBy:     service.SystemLogin().GetAdminID(ctx),
		IsAllowDelete: in.IsAllowDelete,
	}).Where(do.SystemConfig{Id: id}).Update()
	if err != nil {
		return
	}
	if err = s.FlushCache(ctx, []string{in.Code}); err != nil {
		return
	}
	return err
}

func (s *sSystemConfig) DeleteById(ctx context.Context, id int64) (err error) {
	detail, err := s.GetDetailByID(ctx, id)
	if err != nil {
		return
	}
	if detail.IsAllowDelete != 1 {
		err = gerror.New("该配置项不允许删除")
		return
	}
	_, err = dao.SystemConfig.Ctx(ctx).Data(do.SystemConfig{
		DeletedBy: service.SystemLogin().GetAdminID(ctx),
		DeletedAt: gtime.Now(),
	}).Where(do.SystemConfig{Id: id}).Update()
	if err != nil {
		return
	}
	if err = s.DeleteCacheByCode(ctx, detail.Code); err != nil {
		return
	}
	return err
}

func (s *sSystemConfig) List(ctx context.Context, in model.SystemConfigListInput) (configs []model.SystemConfigListItem, total int, err error) {
	configs = make([]model.SystemConfigListItem, 0)
	where := g.Map{}
	if len(in.Code) > 0 {
		where["code like ?"] = "%" + in.Code + "%"
	}
	if len(in.Name) > 0 {
		where["name like ?"] = "%" + in.Name + "%"
	}
	if in.CategoryId > 0 {
		where["category_id"] = in.CategoryId
	}
	err = dao.SystemConfig.Ctx(ctx).Where(where).Page(in.Page, in.PageSize).ScanAndCount(&configs, &total, true)
	if err != nil {
		return
	}
	if total == 0 {
		return
	}

	// 分类信息
	_ = dao.SystemConfigCategory.Ctx(ctx).As("cate").Fields("cate.*").
		WhereIn("cate.id", gdb.ListItemValuesUnique(configs, "CategoryId")).
		ScanList(&configs, "CategoryInfo", "id:CategoryId")

	// 创建人
	_ = dao.SystemUser.Ctx(ctx).As("u").Fields("u.*").
		WhereIn("u.id", gdb.ListItemValuesUnique(configs, "CreatedBy")).
		ScanList(&configs, "CreatedAdmin", "id:created_by")

	// 更新人
	_ = dao.SystemUser.Ctx(ctx).As("u").Fields("u.*").
		WhereIn("u.id", gdb.ListItemValuesUnique(configs, "UpdatedBy")).
		ScanList(&configs, "UpdatedAdmin", "id:updated_by")

	return
}

func (s *sSystemConfig) MapList(ctx context.Context, codes []string) (listMap map[string]model.SystemConfigListMapItem, err error) {
	items := make([]model.SystemConfigListMapItem, 0)
	listMap = make(map[string]model.SystemConfigListMapItem)
	err = dao.SystemConfig.Ctx(ctx).Where(do.SystemConfig{
		Code: codes,
	}).Scan(&items)
	if err != nil {
		return
	}

	for _, item := range items {
		listMap[item.Code] = item
	}

	return
}

func (s *sSystemConfig) GetDetailByCode(ctx context.Context, code string) (result model.SystemConfigListMapItem, err error) {
	result = model.SystemConfigListMapItem{}
	err = dao.SystemConfig.Ctx(ctx).Where(do.SystemConfig{Code: code}).Limit(1).Scan(&result)
	if errors.Is(err, sql.ErrNoRows) {
		return result, gerror.New("暂无配置项")
	}
	return result, err
}

func (s *sSystemConfig) GetDetailByID(ctx context.Context, id int64) (result model.SystemConfigListMapItem, err error) {
	result = model.SystemConfigListMapItem{}
	err = dao.SystemConfig.Ctx(ctx).Where(do.SystemConfig{Id: id}).Limit(1).Scan(&result)
	if errors.Is(err, sql.ErrNoRows) {
		return result, gerror.New("暂无配置项")
	}
	return result, err
}

func (s *sSystemConfig) FlushCache(ctx context.Context, codes []string) (err error) {
	defer func() {
		if err != nil {
			g.Log().Infof(ctx, "flushCache[%v] error: %s", codes, err.Error())
		} else {
			g.Log().Infof(ctx, "flushCache[%v] success", codes)
		}
	}()
	//查询数据
	items := make([]entity.SystemConfig, 10)
	where := g.Map{}
	if len(codes) > 0 {
		where["code"] = codes
	}
	err = dao.SystemConfig.Ctx(ctx).Where(where).Scan(&items)
	if err != nil {
		return
	}

	//写入缓存
	data := map[string]interface{}{}
	for _, item := range items {
		data[item.Code] = item.Content
	}
	err = g.Redis().HMSet(ctx, consts.CacheHashSystemConfigData, data)
	if err != nil {
		return
	}
	return
}

// GetContentByCode 获取配置项内容
func (s *sSystemConfig) GetContentByCode(ctx context.Context, code string) (content string, err error) {
	// 读取缓存
	content, err = s.GetCacheContentByCode(ctx, code)
	if err != nil {
		g.Log().Errorf(ctx, "getContentByCode[%s],error: %s", code, err.Error())
		return
	}
	if len(content) > 0 {
		return content, nil
	}

	//刷新缓存
	if err = s.FlushCache(ctx, []string{code}); err != nil {
		return "", err
	}

	//再次读取缓存
	return s.GetCacheContentByCode(ctx, code)
}

func (s *sSystemConfig) GetCacheContentByCode(ctx context.Context, code string) (content string, err error) {
	result, err := g.Redis().HGet(ctx, consts.CacheHashSystemConfigData, code)
	if err != nil {
		return
	}
	return result.String(), nil
}

func (s *sSystemConfig) DeleteCacheByCode(ctx context.Context, code string) (err error) {
	_, err = g.Redis().HDel(ctx, consts.CacheHashSystemConfigData, code)
	if err != nil {
		return
	}
	return
}

// GetAdminWebsiteConfig 获取后台前端所需的配置
func (s *sSystemConfig) GetAdminWebsiteConfig(ctx context.Context) (data model.AdminWebsiteData, err error) {
	data = model.AdminWebsiteData{}
	// 网站名称
	data.BaseAdminWebsiteName, _ = service.SystemConfig().GetContentByCode(ctx, consts.ConfigCodeBaseAdminWebsiteName)
	// 网站logo
	data.BaseAdminWebsiteLogo, _ = service.SystemConfig().GetContentByCode(ctx, consts.ConfigCodeBaseAdminWebsiteLogo)
	return data, err
}
